<script setup>
import { isRef, reactive, ref, toRef, unref, toRefs, watchEffect, readonly, isReadonly, shallowReadonly } from "vue";
import { useSomeFeature } from './useSomeFeature';

const props = defineProps(['msg'])

// 1. isRef() 检查某个值是否是ref
const name = ref('zz')
let a = 1
const info = reactive({})
console.log(isRef(name)); // true
console.log(isRef(a)); // false
console.log(isRef(info)); // false

// 2. unref()​
// 如果参数是 ref，则返回内部值，否则返回参数本身。这是 val = isRef(val) ? val.value : val 计算的一个语法糖。
console.log(unref(name)); // zz
console.log(unref(a)); // 1

// 3. toRef()​
// 基于响应式对象上的一个属性，创建一个对应的 ref。这样创建的 ref 与其源属性保持同步：改变源属性的值将更新 ref 的值，反之亦然。
const state = reactive({
  foo: 1,
  boo: 2
})
const myFoo = toRef(state, 'foo')
// 更改该 ref 会更新源属性
myFoo.value++
console.log(state.foo); // 2
// 更改源属性也会更新该 ref
state.foo++
console.log(myFoo.value); // 3

console.log('==================');

console.log(props);
console.log(useSomeFeature(toRef(props, 'msg')));
console.log(useSomeFeature(toRef(props, 'msg1')));
// toRefs 在调用时只会为源对象上可以枚举的属性创建 ref。如果要为可能还不存在的属性创建 ref，请改用 toRef。
// console.log(useSomeFeature(toRefs(props)));
// 4. toRefs()​
// 将一个响应式对象转换为一个普通对象，这个普通对象的每个属性都是指向源对象相应属性的 ref。每个单独的 ref 都是使用 toRef() 创建的。
const state1 = reactive({
  foo: 1,
  bar: 2
})

const stateAsRefs = toRefs(state1)
/*
stateAsRefs 的类型：{
  foo: Ref<number>,
  bar: Ref<number>
}
*/

// 这个 ref 和源属性已经“链接上了”
state1.foo++
console.log(stateAsRefs.foo.value) // 2

stateAsRefs.foo.value++
console.log(state1.foo) // 3

function useFeatureX() {
  const state = reactive({
    foo: 1,
    bar: 2
  })
  // 异步操作
  setTimeout(() => {
    state.foo++
  })

  // 在返回时都转为 ref
  return toRefs(state)
  // return state
}

// 可以解构而不会失去响应性
const { foo } = useFeatureX()
watchEffect(() => {
  console.log(foo.value); // 1 1秒后显示2
  // console.log(foo); // 1
})

// 5. isProxy()​
// 检查一个对象是否是由 reactive()、readonly()、shallowReactive() 或 shallowReadonly() 创建的代理。

// 6. isReactive()​
// 检查一个对象是否是由 reactive() 或 shallowReactive() 创建的代理。

// 7. isReadonly()​
// 检查传入的值是否为只读对象。只读对象的属性可以更改，但他们不能通过传入的对象直接赋值。
// 通过 readonly() 和 shallowReadonly() 创建的代理都是只读的
const myObj = readonly({
  a: 1,
  b: {
    c: 2
  }
})
const myObj2 = shallowReadonly({
  a: 1,
  b: {
    c: 2
  }
})
console.log(isReadonly(myObj));
console.log(isReadonly(myObj2));
</script>

<template></template>
